
package com.hlkj.pay.util;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.hlkj.framework.caches.service.RedisTemplateService;
import com.hlkj.pay.enums.PayOrderEnums;

import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/10/10 15:30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderCodeUtil {

    private final RedisTemplateService redisTemplateService;

    private static final String REDIS_KEY = "pay:order_code:";

    private static final int STRING_LENGTH = 9;

    // 定义日期格式化模式
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    @Value("${server.port}")
    private Integer serverPort;

    private String generateRandomString(Integer codeLength) {
        // 使用雪花算法生成ID
        long snowflakeId = IdUtil.getSnowflake(serverPort % 8020, 1).nextId(); // 生成雪花ID
        // 将 Snowflake ID 转换为字符串
        String snowflakeStr = String.valueOf(snowflakeId);
        if (codeLength > snowflakeStr.length()) {
            return snowflakeStr;
        }
        return snowflakeStr.substring(snowflakeStr.length() - codeLength);
    }

    /**
     * 
     * @param orderNoType
     */
    public String orderNo(PayOrderEnums.ORDER_NO_TYPE orderNoType) {
        return orderNo(orderNoType, 1, STRING_LENGTH);
    }

    /**
     * 
     * @param prefix
     */
    public String orderNo(String prefix, Integer codeLength) {
        if (codeLength == null) {
            codeLength = STRING_LENGTH;
        }
        return orderNo(prefix, 1, codeLength);
    }

    /**
     *
     * @param prefix
     * @param time
     * @param codeLength
     */
    public String orderNo(String prefix, Integer time, Integer codeLength) {
        if (codeLength == null) {
            codeLength = STRING_LENGTH;
        }
        if (time > 10) {
            return null;
        }
        StringBuilder sb = new StringBuilder(prefix);
        ZonedDateTime now = ZonedDateTime.now(); // 获取当前系统时间
        ZonedDateTime shanghaiTime = now.withZoneSameInstant(ZoneId.of("Asia/Shanghai"));
        String formattedDate = shanghaiTime.format(formatter);

        sb.append(formattedDate);
        sb.append(generateRandomString(codeLength));
        String code = sb.toString();
        String key = REDIS_KEY + code;
        RLock lock = redisTemplateService.getLock(key);
        boolean tryLock = lock.tryLock();
        if (!tryLock) {
            return orderNo(prefix, time + 1, codeLength);
        }
        redisTemplateService.expire(key, 1);
        return code;
    }

    /**
     *
     * @param orderNoType
     */
    public String orderNo(PayOrderEnums.ORDER_NO_TYPE orderNoType, Integer codeLength) {
        if (codeLength == null) {
            codeLength = STRING_LENGTH;
        }
        return orderNo(orderNoType, 1, codeLength);
    }

    /**
     *
     * @param orderNoType
     */
    public String orderNo(PayOrderEnums.ORDER_NO_TYPE orderNoType, Integer time, Integer codeLength) {
        if (codeLength == null) {
            codeLength = STRING_LENGTH;
        }
        if (time > 10) {
            return null;
        }
        return orderNo(orderNoType.getCode(), time, codeLength);
    }

}
